package com.luxiu.extensionlib.dropDown

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.PopupWindow
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.luxiu.extensionlib.R
import kotlin.math.max


/**
 * val mTopRightMenu = DropDownMenu(this)
 *             val menuItems: MutableList<MenuItem> = ArrayList()
 *             menuItems.add(MenuItem("发起多人聊天"))
 *             menuItems.add(MenuItem("加好友"))
 *             menuItems.add(MenuItem("扫一扫"))
 *
 *             // 设置菜单属性
 *             mTopRightMenu
 *                 .setIconShown(showIcon) // 显示菜单图标，默认为true
 *                 .setBackgroundGray(dimBg) // 背景变暗，默认为true
 *                 .setAnimationShown(needAnim) // 显示动画，默认为true
 *                 .setCardElevation(0f)
 *                 .setCardCornerRadius(10f)
 *                 .addMenuList(menuItems)
 *                 .addMenuItem(MenuItem("面对面快传"))
 *                 .addMenuItem(MenuItem("付款"))
 *                 .setOnMenuItemClickListener { position ->
 *                     Toast.makeText(this@MainActivity, "点击菜单:$position", Toast.LENGTH_SHORT).show()
 *                 }
 *
 *             mTopRightMenu.showAsDropDown(mBinding.test,100,0)
 */

open class DropDownMenu(private val mContext: Activity) {

    private var mParentPopupWindow: PopupWindow
    private var mChildPopupWindow: PopupWindow? = null
    private var mRecyclerView: RecyclerView
    private var mCardView: CardView
    private var mRootView: View = LayoutInflater.from(mContext).inflate(R.layout.layout_drop_down_menu, null)
    private var mParentAdapter: DropDownMenuAdapter
    private var mChildAdapter: DropDownMenuAdapter? = null
    private var mMenuItemList: MutableList<MenuItem> = ArrayList()
    private var mChildMenuItemList: HashMap<Int, ArrayList<MenuItem>> = HashMap()

    private var popHeight = RecyclerView.LayoutParams.WRAP_CONTENT
    private var popWidth = RecyclerView.LayoutParams.WRAP_CONTENT
    private var isIconShown = false
    private var isBackgroundGray = true
    private var isAnimationShown = true

    private val alpha = 0.75f
    private val spaceVertical = 30f
    private val spaceHorizontal = 10f

    private var mChildListener: OnMenuItemClickListener? = null

    init {
        mCardView = mRootView.findViewById(R.id.mCard)
        mRecyclerView = mRootView.findViewById(R.id.mRecyclerview)
        mRecyclerView.layoutManager = LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)
        mRecyclerView.overScrollMode = View.OVER_SCROLL_NEVER

        mParentAdapter = DropDownMenuAdapter(mContext, this, mMenuItemList, isIconShown)
        mRecyclerView.adapter = mParentAdapter

        mParentPopupWindow = PopupWindow(mContext)
        mParentPopupWindow.contentView = mRootView
        mParentPopupWindow.height = popHeight
        mParentPopupWindow.width = popWidth

        mParentPopupWindow.isFocusable = true
        mParentPopupWindow.isOutsideTouchable = true
        mParentPopupWindow.setBackgroundDrawable(ColorDrawable())
        mParentPopupWindow.setOnDismissListener {
            if (isBackgroundGray) {
                setBackgroundAlpha(alpha, 1f, 300)
            }
        }



        mCardView.radius = 20f
        mCardView.elevation = 0f

    }

    /**
     * 设置圆角
     */
    fun setCardCornerRadius(px: Float): DropDownMenu = apply {
        mCardView.radius = px
    }

    /**
     * 设置阴影
     */
    fun setCardElevation(px: Float): DropDownMenu = apply {
        mCardView.elevation = px
    }

    /**
     * 设置背景色
     */
    fun setBackground(colorResId: Int): DropDownMenu = apply {
        val color = ContextCompat.getColor(mContext, colorResId)
        val drawable = ColorDrawable(color)
        mRecyclerView.background = drawable
    }

    /**
     * 是否显示菜单图标
     */
    fun setIconShown(to: Boolean): DropDownMenu = apply {
        this.isIconShown = to
        mParentAdapter.setShowIcon(to)
    }

    /**
     * 添加单个菜单
     */
    fun addMenuItem(item: MenuItem): DropDownMenu = apply {
        mMenuItemList.add(item)
    }

    /**
     * 添加多个菜单
     */
    fun addMenuList(list: List<MenuItem>): DropDownMenu = apply {
        mMenuItemList.addAll(list)
    }

    fun addChildMenuItem(code: Int, item: MenuItem): DropDownMenu = apply {
        mChildMenuItemList.getOrPut(code) { ArrayList() }.add(item)
    }

    fun addChildMenuList(code: Int, list: ArrayList<MenuItem>): DropDownMenu = apply {
        mChildMenuItemList.getOrPut(code) { ArrayList() }.addAll(list)
    }

    /**
     * 是否背景变灰
     */
    fun setBackgroundGray(to: Boolean): DropDownMenu = apply {
        this.isBackgroundGray = to
    }

    /**
     * 是否显示动画
     */
    fun setAnimationShown(to: Boolean): DropDownMenu = apply {
        this.isAnimationShown = to
    }

    fun setParentOnMenuItemClickListener(listener: OnMenuItemClickListener?): DropDownMenu = apply {
        if (mParentAdapter.listener != null) {
            mParentAdapter.setOnMenuItemClickListener(null)
        }
        mParentAdapter.setOnMenuItemClickListener(listener)
    }

    fun setChildOnMenuItemClickListener(listener: OnMenuItemClickListener?): DropDownMenu = apply {
        mChildListener = listener
    }

    fun forTest(anchor: View, x: Int, y: Int) {
        mParentPopupWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, x, y)
    }

    fun showAtViewCenter(rootView: View) {
        val middle = rootView.x + rootView.measuredWidth / 2
        showAtLocation(rootView, middle.toInt())
    }

    fun showAtLocation(anchor: View, inScreenX: Int): DropDownMenu = apply {
        if (mParentPopupWindow.isShowing) return@apply

        val displayMetrics = mContext.resources.displayMetrics
        val screenWidth = displayMetrics.widthPixels
        val screenHeight = displayMetrics.heightPixels

        mParentPopupWindow.contentView.measure(
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
        )

        val viewWidth = anchor.measuredWidth
        val viewHeight = anchor.measuredHeight

        val menuWidth = mParentPopupWindow.contentView.measuredWidth
        val menuHeight = mParentPopupWindow.contentView.measuredHeight

        val location = IntArray(2)
        anchor.getLocationOnScreen(location)
        val anchorScreenX = location[0]
        val anchorScreenY = location[1]

        //当前点击位置是否是在边缘
        val fullRight = screenWidth - inScreenX < menuWidth / 2 + spaceHorizontal
        val fullLeft = inScreenX < menuWidth / 2 + spaceHorizontal
        val fullBelow = screenHeight - anchorScreenY - viewHeight < menuHeight + spaceVertical

        var yLocation = 0f
        var xLocation = 0f

        yLocation = if (fullBelow) {
            //在上方展示，向上偏移
            anchorScreenY - menuHeight - spaceVertical
        } else {
            //可以在下方展示开，出现的位置是View向下偏移
            spaceVertical + viewHeight + anchorScreenY
        }
        xLocation = if (fullRight) {
            //右侧放不开，贴边显示
            screenWidth - menuWidth - spaceHorizontal
        } else if (fullLeft) {
            //左侧放不开，贴左侧显示
            spaceHorizontal
        } else {
            inScreenX - menuWidth / 2f
        }

        if (isAnimationShown) {
            if (fullBelow) {
                mParentPopupWindow.animationStyle = R.style.DropDownMenu_AnimStyle_Up
            } else {
                mParentPopupWindow.animationStyle = R.style.DropDownMenu_AnimStyle_Down
            }
        }

        mParentPopupWindow.showAtLocation(
            mContext.window.decorView, Gravity.TOP or Gravity.START, xLocation.toInt(), yLocation.toInt()
        )

        if (isBackgroundGray) {
            setBackgroundAlpha(1f, alpha, 240)
        }
    }

    fun showChildMenu(code: Int, anchorScreenX: Int, anchorScreenY: Int, viewWidth: Int, viewHeight: Int) {

        val childList = mChildMenuItemList[code]
        if (childList.isNullOrEmpty()) return

        val mChildView: View = LayoutInflater.from(mContext).inflate(R.layout.layout_drop_down_menu, null)

        val mChildCard: CardView = mChildView.findViewById(R.id.mCard)
        val mRecyclerView: RecyclerView = mChildView.findViewById(R.id.mRecyclerview)
        mRecyclerView.layoutManager = LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)
        mRecyclerView.overScrollMode = View.OVER_SCROLL_NEVER
        mChildAdapter = object : DropDownMenuAdapter(mContext, this, childList, isIconShown) {
            override fun checkSelectable(menuItem: MenuItem): Boolean {
                //传的是子菜单
                return checkChildSelectable(menuItem)
            }
        }
        mChildAdapter?.setOnMenuItemClickListener(mChildListener)
        mRecyclerView.adapter = mChildAdapter

        mChildPopupWindow = PopupWindow(mContext)

        mChildPopupWindow?.let{
            it.contentView= mChildView
            it.height = popHeight
            it.width = popWidth
            it.isFocusable = true
            it.isOutsideTouchable = true
            it.setBackgroundDrawable(ColorDrawable())
        }

        mChildCard.radius = 20f
        mChildCard.elevation = 0f


        //首先需要获取，点击的那个menu的绘制区域，然后确认是否展示得开
        val displayMetrics = mContext.resources.displayMetrics
        val screenWidth = displayMetrics.widthPixels
        val screenHeight = displayMetrics.heightPixels

        mChildPopupWindow!!.contentView.measure(
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
        )

        val menuWidth = mChildPopupWindow!!.contentView.measuredWidth
        val menuHeight = mChildPopupWindow!!.contentView.measuredHeight

        //当前点击位置是否是在边缘
        val fullRight = screenWidth - anchorScreenX - viewWidth < menuWidth + spaceHorizontal
        val fullBelow = screenHeight - anchorScreenY < menuHeight + spaceVertical

        var yLocation = 0
        var xLocation = 0f

        yLocation = if (fullBelow) {
            //在上方展示，向上偏移
            anchorScreenY + viewHeight - menuHeight
        } else {
            //可以在下方展示开，出现的位置是View向下偏移
            anchorScreenY
        }
        xLocation = if (fullRight) {
            //右侧放不开，在左边显示
            anchorScreenX - menuWidth - spaceHorizontal
        } else {
            //左侧放不开，右侧显示
            anchorScreenX + viewWidth + spaceHorizontal
        }

        if (isAnimationShown) {
            if (fullRight) {
                mChildPopupWindow!!.animationStyle = R.style.DropDownMenu_AnimStyle_Left
            } else {
                mChildPopupWindow!!.animationStyle = R.style.DropDownMenu_AnimStyle_Right
            }
        }

        mChildPopupWindow!!.showAtLocation(
            mContext.window.decorView, Gravity.TOP or Gravity.START, xLocation.toInt(), yLocation
        )
        mChildPopupWindow!!.setOnDismissListener {
            mParentAdapter.resetClickedItemBackground()
        }
    }

    open fun checkChildSelectable(menuItem: MenuItem) = true

    fun updateMenuItem(newMenuItems: ArrayList<MenuItem>) {
        val oldList = mMenuItemList
        if (mMenuItemList.isEmpty()) {
            for (i in 0 until newMenuItems.size) mParentAdapter.notifyItemChanged(i)
        } else {

            val diffCallback = MenuItemDiffCallback(mMenuItemList, newMenuItems)
            val diffResult = DiffUtil.calculateDiff(diffCallback)

            diffResult.dispatchUpdatesTo(mParentAdapter)
            mMenuItemList = newMenuItems
        }
        mMenuItemList = newMenuItems
    }

    fun exchangeChildMenuItem(parentCode: Int, newChildMenuItems: ArrayList<MenuItem>) {
        if (mChildAdapter == null) return
        val oldList = mChildMenuItemList[parentCode]
        if (oldList.isNullOrEmpty()) {
            mChildMenuItemList[parentCode] = newChildMenuItems
            for (i in 0 until newChildMenuItems.size) mChildAdapter?.notifyItemChanged(i)
        } else {

            val diffCallback = MenuItemDiffCallback(oldList, newChildMenuItems)
            val diffResult = DiffUtil.calculateDiff(diffCallback)

            diffResult.dispatchUpdatesTo(mChildAdapter!!)
            mChildMenuItemList[parentCode] = newChildMenuItems
        }
    }

    private fun setBackgroundAlpha(from: Float, to: Float, duration: Int) {
        val lp = mContext.window.attributes
        val animator = ValueAnimator.ofFloat(from, to)
        animator.duration = duration.toLong()
        animator.addUpdateListener { animation ->
            lp.alpha = animation.animatedValue as Float
            mContext.window.attributes = lp
        }
        animator.start()
    }

    fun dismiss() {
        if (mChildPopupWindow != null && mChildPopupWindow!!.isShowing) {
            mChildPopupWindow!!.setOnDismissListener {
                if (mParentPopupWindow.isShowing) {
                    mParentPopupWindow.dismiss()
                }
            }
            mChildPopupWindow!!.dismiss()
        } else if (mParentPopupWindow.isShowing) {
            mParentPopupWindow.dismiss()
        }
    }

    fun interface OnMenuItemClickListener {
        fun onMenuItemClick(code: Int)
    }

    open inner class DropDownMenuAdapter(
        private val mContext: Context,
        private val mDropDownMenu: DropDownMenu,
        private var menuItemList: List<MenuItem>,
        private var isIconShown: Boolean,
    ) : RecyclerView.Adapter<DropDownMenuAdapter.DropDownMenuViewHolder>() {
        var listener: OnMenuItemClickListener? = null
        private var clickedViewHolder: DropDownMenuViewHolder? = null

        @SuppressLint("NotifyDataSetChanged")
        fun setData(data: List<MenuItem>) {
            menuItemList = data
            notifyDataSetChanged()
        }

        @SuppressLint("NotifyDataSetChanged")
        fun setShowIcon(isIconShown: Boolean) {
            this.isIconShown = isIconShown
            notifyDataSetChanged()
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DropDownMenuViewHolder {
            val view = LayoutInflater.from(mContext).inflate(R.layout.item_drop_down_menu, parent, false)
            return DropDownMenuViewHolder(view)
        }

        override fun onBindViewHolder(holder: DropDownMenuViewHolder, position: Int) {
            val menuItem = menuItemList[position]
            if (isIconShown) {
                holder.icon.visibility = View.VISIBLE
                val resId = menuItem.icon
                holder.icon.setImageResource(max(resId.toDouble(), 0.0).toInt())
            } else {
                holder.icon.visibility = View.GONE
            }
            holder.text.text = menuItem.text
            if (checkSelectable(menuItemList[position])) {
                holder.text.alpha = 1f
                //可以再加个对号之类的表示已被选中
                holder.selectedIcon.visibility = View.GONE
            } else {
                holder.text.alpha = 0.5f
                holder.selectedIcon.visibility = View.VISIBLE
            }
            holder.container.setOnClickListener {
                if (mChildMenuItemList.containsKey(menuItem.code) && !mChildMenuItemList[menuItem.code].isNullOrEmpty()) {
                    clickedViewHolder = holder
                    holder.container.alpha = 0.5f
                    holder.container.alpha = 0.5f
                    val location = IntArray(2)
                    holder.container.getLocationOnScreen(location)
                    val anchorScreenX = location[0]
                    val anchorScreenY = location[1]
                    mDropDownMenu.showChildMenu(
                        menuItem.code, anchorScreenX, anchorScreenY, holder.container.width, holder.container.height
                    )
                } else if (!checkSelectable(menuItemList[position])) {
                    //二级菜单不可选，一级菜单默认返回true
                    Log.d("June", "选项不可点击，原因可能是已经被选中过了或者已经在添加的表里了")
                } else if (listener != null) {
                    mDropDownMenu.dismiss()
                    listener!!.onMenuItemClick(menuItem.code)
                }
            }
        }

        open fun checkSelectable(menuItem: MenuItem) = true

        override fun getItemCount(): Int {
            return menuItemList.size
        }

        inner class DropDownMenuViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            var container: ViewGroup = itemView as ViewGroup
            var icon: ImageView = itemView.findViewById(R.id.mItemIcon)
            var text: TextView = itemView.findViewById(R.id.mItemText)
            var selectedIcon: ImageView = itemView.findViewById(R.id.ItemSelected)
        }

        fun setOnMenuItemClickListener(listener: OnMenuItemClickListener?) {
            this.listener = listener
        }

        fun resetClickedItemBackground() {
            clickedViewHolder?.let {
                it.container.alpha = 1.0f
                clickedViewHolder = null
            }
        }
    }
}

class MenuItem(
    var text: String? = null,
    var icon: Int = 0,
    var code: Int = 0,
)

class MenuItemDiffCallback(
    private val oldList: List<MenuItem>,
    private val newList: List<MenuItem>,
) : DiffUtil.Callback() {

    override fun getOldListSize(): Int = oldList.size

    override fun getNewListSize(): Int = newList.size

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition].code == newList[newItemPosition].code
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val oldItem = oldList[oldItemPosition]
        val newItem = newList[newItemPosition]
        return oldItem.code == newItem.code && oldItem.icon == newItem.icon && oldItem.text == newItem.text

    }
}